home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-09-17 | 7.5 KB | 193 lines | [TEXT/MPS ] |
- { Zap (Xap):
- a dcmd to zap the handles and pointers as they are disposed.
-
- Copyright © 1991 by Apple Computer, Inc., all rights reserved.
-
- by Bo3b Johnson 1/10/91
- MS 37-DS
- for best viewing, use Palatino 12.
-
- 5/22/91: Made it version 2 for release to world.
- Cleaned up comments.
-
- 10/9/91: Renamed all files to Xap and changed the makefile 'cuz there are too many
- lawyers in the world and one of them discovered that someone has a trademark on
- the name Zap and insisted. The dcmd itself is still named "Zap" 'cuz it has to be.
- –Dave Johnson
- }
-
- UNIT Zap;
-
- (*
- Build this dude using the Build Menu, it has a make file.
-
- The basic idea here is to trash the blocks in the heap as they are disposed, in order
- to flush out any use of memory that has been disposed. This thing will patch the
- traps DisposPtr and DisposHandle, and when they are called, it will fill the entire
- block with $50FFC001 as a funky number that may cause bus errors if used in an
- inappropriate situation. As it runs, more and more of the memory will be filled
- with these numbers, so it can also find some use of uninitialized variables.
-
- Notably, you can't really run this during boot time, since the system is a little
- to weird, and a number of Inits do things like dispose the block the pc is running
- out of. With Zap on, the code stream gets filled with illegal instructions, and you
- find out who is being sick. (Like a lot of these things, it isn't strictly a bug, since it
- won't crash in the normal case, it's just a bad idea.)
-
- The options are: Zap On|Off
- Off by default, naturally, and it doesn't toggle, although perhaps it should, instead
- of requiring a parameter.
-
- Things to do:
- Could patch the NewPtr/NewHandle side too, to trash the blocks at allocation.
- That might slow it down too much though.
- Could be restructured a bit to make it easier to figure out, since it started from the
- leaks source, it has some things that aren't really needed here.
- Are the patches 32 bit clean? I'm not sure if it is cool given the early load time.
- Will it work on Mac+ machines? LongWord stomping?
- Should patch MultiFinder trap too, to do it's blocks.
- *)
-
- {$R-}
- {$D+} { debug labels on. }
-
- INTERFACE
-
- USES MemTypes, Resources, Traps, Memory, OSUtils, Events,
- dcmd; { Macsbug interface routines. }
-
-
- { Public declaration for dcmdGlue. Must be in every dcmd. The name cannot be changed. }
- PROCEDURE CommandEntry (paramPtr: dcmdBlockPtr);
-
-
- IMPLEMENTATION
-
-
- { They don't
- really have to be globals, but it is a convenience. I label them with a p, so that you can
- immediately see they are private globals (to this unit), a quality MacApp convention. }
- VAR pDumpString: Str255; { To dump label info, from symbols in code. }
-
- {---------------------------------------------------------------------------------------------------------------------------------}
-
- { Set the address of NewPtr before I patch the trap. This is so the assembly interface can
- find this address again, when it is called as part of a NewPtr trap. This is required because
- I really need PC-relative addressing in order to be able to get this old address. Both
- of the routines I patch have the same problem, so I have an interface for each. The
- asm routine just saves off the address passed in, as a PC-Relative variable. }
- PROCEDURE SetOldDisposPtr (address: LongInt); EXTERNAL;
- PROCEDURE SetOldDisposHandle (address: LongInt); EXTERNAL;
-
-
- { The references to the asm routines. }
- PROCEDURE WatchDisposPtr; EXTERNAL;
- PROCEDURE WatchDisposHandle; EXTERNAL;
-
- { When I start up this zapping universe, I have to set the variables used by the
- assembly patch code. }
- PROCEDURE SetActive (state: Boolean); EXTERNAL;
-
-
- {---------------------------------------------------------------------------------------------------------------------------------}
- { This is an init routine that sets up the trap patches, and creates and inits the block in
- the system heap that is used to store the records that track each block I see go by. This
- is a hard-coded tracking size, which is bad. This part uses the toolbox, which is a bad
- idea for dcmds to do. If I can't get space for the buffer, I won't install the patches,
- and I'll beep to let them know. Just added the dcmdSwapWorlds to make it work
- with TMon Pro. }
- PROCEDURE CreateZapper;
-
- BEGIN
- { Be sure that the dcmd is turned off when we start. }
- SetActive (FALSE);
-
- { Patch the traps.... These are being patched in the world, not in the debugger world. }
- { Switch over to the real world, in case the debugger does world swaps. TMon Pro.}
- dcmdSwapWorlds;
-
- { Use NGetTrapAddress since it is always safer on current machines. Take the result
- it gives me, and save it off in asm land, for future reference. Then, move in the
- new address of the routine, my asm glue, with stomping junk. }
- { Do DisposPtr }
- SetOldDisposPtr (NGetTrapAddress(_DisposPtr, OSTrap));
- NSetTrapAddress(ORD(@WatchDisposPtr), _DisposPtr, OSTrap);
-
- { Do DisposHandle, too. }
- SetOldDisposHandle (NGetTrapAddress(_DisposHandle, OSTrap));
- NSetTrapAddress(ORD(@WatchDisposHandle), _DisposHandle, OSTrap);
-
- { Switch back to debugger world. }
- dcmdSwapWorlds;
- END; { CreateLeakWatcher }
-
- {---------------------------------------------------------------------------------------------------------------------------------}
- { Well, I stole this routine from MacApp utilities. I want to lower case the strings so I
- don't have case sensitivities. This will do it, without using the toolbox. }
- PROCEDURE LowerStr255(VAR s: Str255);
-
- VAR i: INTEGER;
-
- BEGIN
- FOR i := 1 TO LENGTH(s) DO
- IF (s[i] IN ['A'..'Z']) THEN
- s[i] := CHR(Ord(s[i]) + 32)
- END; { LowerStr255 }
-
-
- {---------------------------------------------------------------------------------------------------------------------------------}
- { If something was not understood, dump the info for how this works. }
- PROCEDURE DumpHelpInfo;
-
- BEGIN
- dcmdDrawLine ('Zap On|Off');
- dcmdDrawLine (' Zap disposed pointers/handles to $50FFC001. (Version 2)');
- END;
-
- {---------------------------------------------------------------------------------------------------------------------------------}
- {---------------------------------------------------------------------------------------------------------------------------------}
-
- { This fine fellow is the main entry point for the dcmd. It is the hook by which I get called
- by MacsBug to do my thing. It is basically the chance to key off the command line and do
- what they request.
-
- Change the version number in the help, whenever it is re-released. This is the only
- version number in the program. }
- PROCEDURE CommandEntry (paramPtr: DCmdBlockPtr);
-
- VAR ch: CHAR;
-
- BEGIN
- CASE paramPtr^.request OF
- { When I'm called to Init, do the init code of installing the trap patches. }
- dcmdInit:
- CreateZapper;
-
- { I can get various DoIt commands, so parse out the options. If I don't get anything,
- do the standard dump info. I lowercase the string so I can avoid any case sensitivity
- on options passed in. }
- dcmdDoIt:
- BEGIN
- ch := dcmdGetNextParameter (pDumpString);
- LowerStr255 (pDumpString);
- IF pDumpString = 'on' THEN BEGIN
- SetActive (TRUE);
- dcmdDrawLine (' Zap is on');
- END
- ELSE IF pDumpString = 'off' THEN BEGIN
- SetActive (FALSE);
- dcmdDrawLine (' Zap is off');
- END
- ELSE DumpHelpInfo;
- END;
-
- { Give them the obvious help info. }
- OTHERWISE
- DumpHelpInfo;
-
- END; { End of case paramPtr^.request. }
-
- END; { CommandEntry }
-
- END.
-